package com.beidasoft.web.util.fileUtil;




import com.beidasoft.web.config.Ks3ConfigProperties;
import com.beidasoft.web.exception.inspection.InspectionException;
import com.beidasoft.web.model.system.User;
import com.beidasoft.web.util.Log4jUtil;
import com.beidasoft.web.util.MinioUtils;
import com.ksyun.ks3.AutoAbortInputStream;
import com.ksyun.ks3.dto.*;
import com.ksyun.ks3.exception.Ks3ServiceException;
import com.ksyun.ks3.service.Ks3Client;
import com.ksyun.ks3.service.Ks3ClientConfig;
import com.ksyun.ks3.service.request.GetObjectRequest;
import io.minio.errors.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

@Component
@Slf4j
public class Ks3Util {
    @Resource
    private Ks3ConfigProperties ks3ConfigProperties;

    @Resource
    private MinioUtils minioUtil;
    private static volatile Ks3Client ks3Client;

    public Ks3Util() {
    }

    public Ks3Client getClient() {
        if (null == ks3Client) {
            synchronized (Ks3Client.class) {
                if (null == ks3Client) {
                    // yourEndpoint填写Bucket所在地域对应的Endpoint。以中国（北京）为例，Endpoint填写为ks3-cn-beijing.ksyuncs.com。如果使用自定义域名，设置endpoint为自定义域名，同时设置domainMode为true
                    String endpoint = ks3ConfigProperties.getEndPoint();
                    // 金山云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用子账号账号进行 API 访问或日常运维，请登录 https://uc.console.ksyun.com/pro/iam/#/user/list 创建子账号。
                    String accessKeyId = ks3ConfigProperties.getAccessKeyId();
                    String accessKeySecret = ks3ConfigProperties.getAccessKeySecret();
                    // 创建Ks3ClientConfig 实例。
                    Ks3ClientConfig config = new Ks3ClientConfig();
                    // 设置域名
                    config.setEndpoint(endpoint);
                    /*
                     * false: （推荐）使用三级域名：{bucketName}.{endpoint}/{objectKey}的形式访问
                     * true:  使用二级域名：{endpoint}/{bucketName}/{objectKey}的形式访问
                     * 如果domainMode设置为true，则pathStyleAccess可忽略设置
                     */
                    config.setPathStyleAccess(false);
                    // 创建Ks3Client实例
                    ks3Client = new Ks3Client(accessKeyId, accessKeySecret, config);
                }
            }
        }
        return ks3Client;
    }

    public void closeKs3Client() {
        if (getClient() != null) {
            log.info("ks3客户端使用完毕进行关闭");
            getClient().shutdown();
        }

    }



    /**
     * 判断文件是否存在
     * @param realPath: 文件真是路径
     * @return: InputStream
     * @date : 2024/4/23
     */
    //已经迁移
    public boolean fileExist(String realPath) {
        realPath = realPath.replaceAll("\\\\", "/");
        realPath = ks3ConfigProperties.getDefaultPath() + "/"+ realPath;
        return getClient().objectExists(ks3ConfigProperties.getBucketName(), realPath);
    }

    public List<String>  listFiles(String realPath) {
        realPath = realPath.replaceAll("\\\\", "/");
        realPath = ks3ConfigProperties.getDefaultPath() + "/"+ realPath;
        ObjectListing objectListing = getClient().listObjects(ks3ConfigProperties.getBucketName(), realPath);
        List<String> files = new ArrayList<>();

        for (int i=0;i < objectListing.getObjectSummaries().size();i++){
            if(i == 0){

            }else {
                String fileName = objectListing.getObjectSummaries().get(i).getKey();
                files.add(StringUtils.substringAfter(fileName,realPath));
            }

        }
        return files;
    }

    /**
     * 上传 MultipartFile 类型文件
     * @param fileRelativePath: 文件保存路径
     * @param uploadFile: 文件
     * @return: InputStream
     * @date : 2024/4/23
     */
    //已经迁移
    public String uploadFile(String fileRelativePath, MultipartFile uploadFile) throws Exception {
        fileRelativePath = ks3ConfigProperties.getDefaultPath() + "/" + fileRelativePath;
        getClient().putObject(ks3ConfigProperties.getBucketName(), fileRelativePath, new ByteArrayInputStream(uploadFile.getBytes()), null);
        String hostUrl = this.getHostUrl();
        return hostUrl + fileRelativePath;
    }

    /**
     * 上传 File 类型文件
     * @param fileRelativePath: 文件保存路径
     * @param file: 文件
     * @return: InputStream
     * @date : 2024/4/23
     */
    //已经迁移
    public String uploadFile(String fileRelativePath, File file) throws Exception {
        fileRelativePath = ks3ConfigProperties.getDefaultPath() + "/" + fileRelativePath;
        getClient().putObject(ks3ConfigProperties.getBucketName(), fileRelativePath, file);
        String hostUrl = this.getHostUrl();
        return hostUrl + fileRelativePath;
    }
    /**
     * 上传  文件流
     * @param fileRelativePath: 文件保存路径
     * @param inputStream: 文件流
     * @return: InputStream
     * @date : 2024/4/23
     */
    //已经迁移
    public String uploadFile(String fileRelativePath, InputStream inputStream) throws Exception {
        fileRelativePath = ks3ConfigProperties.getDefaultPath() + "/" + fileRelativePath;
        Ks3Client client = getClient();
        PutObjectResult putObjectResult = client.putObject(ks3ConfigProperties.getBucketName(), fileRelativePath, inputStream, new ObjectMetadata());
        String hostUrl = this.getHostUrl();
        return hostUrl + fileRelativePath;
    }


    /**
     * 上传本地文件（路径）
     * @param fileRelativePath: 文件保存路径
     * @param filePath: 本地文件实际地址
     * @return: InputStream
     * @date : 2024/4/23
     */
    //已经迁移
    public String uploadFile(String fileRelativePath, String filePath) throws Exception {
        fileRelativePath = ks3ConfigProperties.getDefaultPath() + "/" + fileRelativePath;
        File file = new File(filePath);
        getClient().putObject(ks3ConfigProperties.getBucketName(), fileRelativePath, file);
        String hostUrl = this.getHostUrl();
        return hostUrl + fileRelativePath;
    }

    private String getHostUrl() {
        String hostUrl = "";
        if (ks3ConfigProperties.getEndPoint().startsWith("http://")) {
            hostUrl = "http://".concat(ks3ConfigProperties.getBucketName()).concat(".").concat(ks3ConfigProperties.getEndPoint().replace("http://", "")).concat("/");
        } else if (ks3ConfigProperties.getEndPoint().startsWith("https://")) {
            hostUrl = "https://".concat(ks3ConfigProperties.getBucketName()).concat(".").concat(ks3ConfigProperties.getEndPoint().replace("https://", "")).concat("/");
        }
        return hostUrl;
    }


    /**
     * 删除文件服务器文件（路径）
     * @param realPath: 文件保存路径
     * @return: InputStream
     * @date : 2024/4/23
     */
    //全局已经迁移
    public boolean deleteFile(String realPath) {
        realPath = realPath.replaceAll("\\\\", "/");
        realPath = ks3ConfigProperties.getDefaultPath() + "/" + realPath;
        if (ks3Client.objectExists(ks3ConfigProperties.getBucketName(), realPath)) {
            getClient().deleteObject(ks3ConfigProperties.getBucketName(), realPath);
        }
        return true;
    }


    /**
     * 下载文件 20240423
     * @param realPath: 文件真实路径
     * @param path: 文件路径
     * @return: InputStream
     * @date : 2024/4/23
     */
    //全局迁移
    public void downloadFile(String realPath, String path, HttpServletRequest request, HttpServletResponse response) {
        
        String fileName = "";
        if (StringUtils.isNotBlank(realPath)) {
            fileName = realPath.replaceFirst(path,"");
        }
        realPath = ks3ConfigProperties.getDefaultPath() + "/" + realPath;
        InputStream fis = null;
        OutputStream outputStream = null;
        InputStream uploadInputStream = null;

        String userAgent = request.getHeader("User-Agent");
        try {
            if (userAgent.toLowerCase().indexOf("msie") > 0
                    || userAgent.indexOf("like Gecko") > 0) {
                // IE浏览器
                path = URLEncoder.encode(path, "UTF-8");
            } else {
                // 先去掉文件名称中的空格,然后转换编码格式为utf-8,保证不出现乱码,
                // 这个文件名称用于浏览器的下载框中自动显示的文件名
                path = new String(path.replaceAll(" ", "").getBytes(StandardCharsets.UTF_8), "ISO8859-1");
            }
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        response.addHeader("Content-Disposition", "attachment;filename=" + fileName);//这里设置一下让浏览器弹出下载提示框，而不是直接在浏览器中打开
        response.setContentType("application/octet-stream");

        try {
            // 判断文件是否存在
            if (fileExist(realPath)) {
                GetObjectRequest getObjectRequest = new GetObjectRequest(ks3ConfigProperties.getBucketName(), realPath);
                Ks3Object ks3Object = getClient().getObject(getObjectRequest).getObject();
                // 读取文件内容。
                fis = ks3Object.getObjectContent();
            } else {
                // 兼容minio操作，获取文件流，上传至ks3
                uploadInputStream = minioUtil.downloadFile(realPath);
                uploadFile(realPath, uploadInputStream);
                // 防止文件流关闭，再次获取
                fis = minioUtil.downloadFile(realPath);
            }
            outputStream = response.getOutputStream();
            FileDownloadUtils.copyStream(fis, outputStream);
        } catch (Ks3ServiceException var10) {
            log.error("ks3异常，异常信息为", var10);
        } catch (Exception var9) {
            log.error("文件下载失败，异常信息为", var9);
        }finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    log.error("输入流关闭失败", e);
                }
            }
            if (uploadInputStream != null) {
                try {
                    uploadInputStream.close();
                } catch (IOException e) {
                    log.error("输入流关闭失败", e);
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    log.error("输入流关闭失败", e);
                }
            }
        }

    }


    /*获取文件流    兼容minio*/
    /**
     * 获取文件流
     * objectName:桶名
     * @param realPath: 文件真实路径
     * @return: InputStream
     * @date : 2024/4/23
     */
    //全局迁移
    public InputStream getFileInputStream(String realPath) throws ServerException, InvalidBucketNameException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        try {
            realPath = realPath.replaceAll("\\\\", "/");
            realPath =  ks3ConfigProperties.getDefaultPath() + "/"+ realPath;
            GetObjectResult getObjectResult = getClient().getObject(ks3ConfigProperties.getBucketName(),realPath);
            return getObjectResult.getObject().getObjectContent();

        } catch (Exception e) {
            System.out.println("ks3服务器没有找到对应的文件，因此再次获取Minio文件");

            try {
                InputStream inputStream =MinioUtils.getObject(MinioUtils.bucketName,realPath);
                return inputStream;
            }catch (Exception E){
                System.out.println("两个文件服务器都没有找到文件");
                return null;
            }

        }

    }


    /**
     * 文件服务器内文件复制
     * objectName:桶名
     * @param oldPath: 文件旧真实路径
     * @param newPath: 文件新真实路径
     * @return: InputStream
     * @date : 2024/4/23
     */
    //全局迁移
    public void copyFile(String oldPath,String newPath) throws ServerException, InvalidBucketNameException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        try {
            oldPath = oldPath.replaceAll("\\\\", "/");
            oldPath =  ks3ConfigProperties.getDefaultPath() + "/"+ oldPath;

            newPath = newPath.replaceAll("\\\\", "/");
            newPath =  ks3ConfigProperties.getDefaultPath() + "/"+ newPath;

            //获取旧文件文件流
            InputStream oldInputStream = this.getFileInputStream(oldPath);
            //上传新文件
            this.uploadFile(newPath,oldInputStream);

        } catch (Exception e) {
            System.out.println("文件复制失败");
        }

    }


    //    public void downloadLocalFile(String objectName, String localFileUrl) {
//        objectName = objectName.replaceAll("\\\\", "/");
//        GetObjectResult getObjectResult = ks3Client.getObject(ks3ConfigProperties.getBucketName(), objectName);
//        AutoAbortInputStream inputStream = getObjectResult.getObject().getObjectContent();
//        OutputStream outputStream = null;
//        File tempFile = new File(localFileUrl);
//        try {
//            outputStream = Files.newOutputStream(tempFile.toPath());
//        } catch (Exception e) {
//            throw new RuntimeException(e);
//        }finally {
//            if (outputStream != null) {
//                try {
//                    outputStream.close();
//                } catch (IOException e) {
//                    throw new RuntimeException(e);
//                }
//            }
//            if (inputStream != null) {
//                try {
//                    inputStream.close();
//                } catch (IOException e) {
//                    throw new RuntimeException(e);
//                }
//            }
//        }
//
//    }


    public List<Ks3ObjectSummary> list() {
        ObjectListing objectListing = getClient().listObjects(ks3ConfigProperties.getBucketName());
        return objectListing.getObjectSummaries();
    }

}
